<!DOCTYPE html>
<!-- saved from url=(0058)https://atc1441.github.io/ATC_TLSR_Paper_UART_Flasher.html -->
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<!-- style type="text/css"></style -->
	<title>Hanshow TLSR8359 E-Paper Pricetag Flasher</title>
  </head>
  <body>
	<h3>TLSR8359 USB-COM Flash Writer v0.2 (TX-SWS only!)</h3>
	<div><br>
	<a href="https://github.com/atc1441/ATC_TLSR_Paper" target="_blank">Firmware GitHub Repo</a><br>
	<a href="https://github.com/atc1441/ATC_TLSR_Paper/blob/main/USB_UART_Flashing_connection.jpg" target="_blank">Flashing Pinout</a>
	<br><br>
	1. USB-COM: <input type="button" id="butOpen" value="Close">
	Baud: <select id="ubaud" title="Optimal: 460800 baud"><option value="115200">115200</option><option value="230400">230400</option><option value="460800" selected="">460800</option><option value="921600">921600</option><option value="1500000">1500000</option><option value="2000000">2000000</option></select>
	Atime: <select id="uatime" title="Activation time: Set above than Advertising interval or use manual power reset"><option value="0">0 ms</option><option value="100">100 ms</option><option value="1000">1 sec</option><option value="2000">2 sec</option><option value="3000" selected="">3 sec</option><option value="4000">4 sec</option><option value="8000">8 sec</option><option value="16000">16 sec</option></select>
	<br><br>
	2. Select Firmware: <input type="file" accept=".bin" id="file"><br><br>
	3. <input type="button" title="Write firmware in to Flash" id="butWrite" value="Write to Flash"> <span id="swrite">ok</span><br><br>
	<input type="button" title="Unlock flash" id="butUnlock" value="Unlock Flash"> <input type="button" title="Clean all flash" id="butErase" value="Erase All Flash"> <input type="button" id="butReset" title="Test restart of M�U" value="Soft Reset MCU"> <input type="button" id="butClrlog" value="Clear log"><br><hr>
	</div>
	<div id="slog">22:53:41: USB-COM opened.<br>22:53:44: File was selected, size: 92424 bytes<br>22:53:46: Reset DTR/RTS (100 ms)<br>22:53:46: Activate (3 sec)...<br>22:53:49: Flash Erase All (3.5 sec)...<br>22:53:53: Done.<br>22:53:53: Reset DTR/RTS (100 ms)<br>22:53:53: Activate (3 sec)...<br>22:53:56: Write 92424 bytes in to Flash...<br>22:54:33: Done (39.818 sec).<br>22:54:33: Soft Reset MCU<br>23:18:42: File was selected, size: 92392 bytes<br>23:18:44: Reset DTR/RTS (100 ms)<br>23:18:44: Activate (3 sec)...<br>23:18:47: Write 92392 bytes in to Flash...<br>23:19:21: Done (36.991 sec).<br>23:19:21: Soft Reset MCU<br>23:23:02: File was selected, size: 92424 bytes<br>23:23:03: Reset DTR/RTS (100 ms)<br>23:23:03: Activate (3 sec)...<br>23:23:06: Write 92424 bytes in to Flash...<br>23:23:40: Done (36.994 sec).<br>23:23:40: Soft Reset MCU<br>00:33:54: File was selected, size: 92460 bytes<br>00:33:55: Reset DTR/RTS (100 ms)<br>00:33:55: Activate (3 sec)...<br>00:33:58: Flash Erase All (3.5 sec)...<br>00:34:02: Done.<br>00:34:02: Reset DTR/RTS (100 ms)<br>00:34:02: Activate (3 sec)...<br>00:34:05: Write 92460 bytes in to Flash...<br>00:34:39: Done (36.881 sec).<br>00:34:39: Soft Reset MCU<br>00:55:09: File was selected, size: 92568 bytes<br>00:55:10: Reset DTR/RTS (100 ms)<br>00:55:10: Activate (3 sec)...<br>00:55:13: Write 92568 bytes in to Flash...<br>00:55:47: Done (36.868 sec).<br>00:55:47: Soft Reset MCU<br></div>
  
<script type="text/javascript">
"use strict";
//Firmware values
var firmwareArray = null;
var $ = function(id) {
	return document.getElementById(id);
}
const connect = $('butOpen');
const fwriter = $('butWrite');
const swrite = $('swrite');
const bunlock = $('butUnlock');
const berase = $('butErase');
const breset = $('butReset');
const ubaud = $('ubaud');
const uatime = $('uatime');
const ufile = $('file');
function log(data) {
	console.log(data);
	$("slog").innerHTML += new Date().toLocaleTimeString() + ": " + data + "<br>";
}
$('butClrlog').onclick = function() {$("slog").innerHTML='';};
function delay(ms) {
	return new Promise((resolve, reject) => {
		setTimeout(resolve, ms);
	});
}
function hex(number, length) {
	var str = (number.toString(16)).toUpperCase();
	while (str.length < length) str = '0' + str;
	return str;
}
function sws_wr_addr(addr, data) {
	// log(addr + ':['+data+']');
	let d = new Uint8Array(10); // word swire 10 bits = 10 bytes UART
	let h = new Uint8Array([0x5a, (addr>>16)&0xff, (addr>>8)&0xff, addr & 0xff, 0x00]);
	let pkt = new Uint8Array((data.byteLength+6)*10);
	d[0] = 0x80; // start bit byte cmd swire = 1
	d[9] = 0xfe; // stop bit swire = 0
	h.forEach((el,n) => {
		let m = 0x80; // mask bit
		let idx = 1;
		do {
			if((el & m) != 0) d[idx] = 0x80;
			else d[idx] = 0xfe;
			idx += 1; m >>= 1;
		} while(m != 0);
		pkt.set(d, n*10);
		d[0] = 0xfe; // start bit next byte swire = 0
	});
	data.forEach((el,n) => {
		let m = 0x80; // mask bit
		let idx = 1;
		do {
			if((el & m) != 0) d[idx] = 0x80;
			else d[idx] = 0xfe;
			idx += 1; m >>= 1;
		} while(m != 0);
		pkt.set(d, (n+5)*10);
	});
	// swire stop cmd = 0xff 
	d.fill(0x80,0,9);
	pkt.set(d, (data.byteLength+5)*10);
	return pkt;
}
async function FlashByteCmd(cmd) { 
	await serialController.write_raw(sws_wr_addr(0x0d, new Uint8Array([0x00]))); // cns low
	return await serialController.write_raw(sws_wr_addr(0x0c, new Uint8Array([cmd & 0xff, 0x01]))); // Flash cmd + cns high
}
async function FlashWriteEnable() { // send flash cmd 0x06 write enable to flash
	return FlashByteCmd(0x06);
}
async function FlashWakeUp() { // send flash cmd 0xab to wakeup flash
	return FlashByteCmd(0xab);
}
async function FlashUnlock() { // send flash cmd 0x01 unlock flash
	await serialController.write_raw(sws_wr_addr(0x0d, new Uint8Array([0x00]))); // cns low
	await serialController.write_raw(sws_wr_addr(0x0c, new Uint8Array([0x01]))); // Flash cmd
	await serialController.write_raw(sws_wr_addr(0x0c, new Uint8Array([0x00]))); // Unlock all
	return await serialController.write_raw(sws_wr_addr(0x0c, new Uint8Array([0x00, 0x01]))); // Unlock all + cns high
}
async function FlashEraseAll() { // send flash cmd 0x60 erase all flash
	return FlashByteCmd(0x60);
}
async function WriteFifo(addr, data) { // send all data to one register (no increment address - fifo mode)
	await serialController.write_raw(sws_wr_addr(0x00b3, new Uint8Array([0x80]))); // [0xb3]=0x80 ext.SWS into fifo mode
	await serialController.write_raw(sws_wr_addr(addr, data)); // send all data to one register (no increment address - fifo mode)
	return await serialController.write_raw(sws_wr_addr(0x00b3, new Uint8Array([0x00]))); // [0xb3]=0x00 ext.SWS into normal(ram) mode
}
async function SectorErase(addr) {
	await FlashWriteEnable();
	await serialController.write_raw(sws_wr_addr(0x0d, new Uint8Array([0x00]))); // cns low
	await serialController.write_raw(sws_wr_addr(0x0c, new Uint8Array([0x20]))); // Flash cmd erase sector
	await serialController.write_raw(sws_wr_addr(0x0c, new Uint8Array([(addr >> 16) & 0xff]))); // Faddr hi
	await serialController.write_raw(sws_wr_addr(0x0c, new Uint8Array([(addr >> 8) & 0xff]))); // Faddr mi
	await serialController.write_raw(sws_wr_addr(0x0c, new Uint8Array([addr & 0xff, 0x01]))); // Faddr lo + cns high
	return await delay(300);
}
async function WriteFlashBlk(addr, data) {
	await FlashWriteEnable();
	await serialController.write_raw(sws_wr_addr(0x0d, new Uint8Array([0x00]))); // cns low
	let blk = new Uint8Array(4 + data.byteLength);
	blk[0] = 0x02;
	blk[1] = (addr >> 16) & 0xff;
	blk[2] = (addr >> 8) & 0xff
	blk[3] = addr & 0xff;
	blk.set(data, 4);
	await WriteFifo(0x0c, blk); // send all data to SPI data register
	await serialController.write_raw(sws_wr_addr(0x0d, new Uint8Array([0x01]))); // cns high
	return await delay(10);
}
async function SoftResetMSU() {
	return await serialController.write_raw(sws_wr_addr(0x06f, new Uint8Array([0x20]))); // Soft Reset MCU
}
async function Activate(tim) {
	let blk = sws_wr_addr(0x0602, new Uint8Array([0x05])); // CPU stop
	let s = 'Reset DTR/RTS (100 ms)';
   	swrite.innerHTML = s;
	log(s);
	await serialController.reset(100); // DTR & RTS
	console.log('Soft Reset MCU');
	await SoftResetMSU();
	s = 'Activate ('+(tim/1000.0)+' sec)...';
   	swrite.innerHTML = s;
	log(s);
	let t = new Date().getTime();
	while(new Date().getTime() - t < tim) {
		await serialController.write_raw(blk); // CPU stop
	}
	await serialController.write_raw(sws_wr_addr(0x00b2, new Uint8Array([55]))); // Set SWS Speed
	await serialController.write_raw(blk);
	return await FlashWakeUp(); 
}
//---------------------------------
async function FlashWrite() {
	if(firmwareArray == null || connect.opened == false)
		return;
	let t = new Date().getTime();
	await Activate(uatime.value);
	log('Write ' + firmwareArray.byteLength + ' bytes in to Flash...');
	let len = firmwareArray.byteLength;
	let addr = 0;
	let sblk = 256; // max spi-flash fifo = 256
	while(len > 0) {
	    if((addr & 0x0fff) == 0) {
	    	let s = Math.floor(addr / (firmwareArray.byteLength * 1.0) * 100) + '% Flash Sector Erase at 0x'+hex(addr, 6);
	    	console.log(s);
	    	swrite.innerHTML = s;
	    	await SectorErase(addr);
	    }
		if(len < sblk) sblk = len;		
    	let s = Math.floor(addr / (firmwareArray.byteLength * 1.0) * 100) + '% Flash Write '+sblk+' bytes at 0x'+hex(addr, 6);
    	console.log(s);
    	swrite.innerHTML = s;
		await WriteFlashBlk(addr, new Uint8Array(firmwareArray.slice(addr, addr + sblk)));
		addr += sblk;
		len -= sblk;
	}
   	swrite.innerHTML = 'ok';
	log('Done ('+((new Date().getTime()-t)/1000.0)+' sec).');
	log('Soft Reset MCU');
	return await SoftResetMSU();
}
async function DeviceStop() {
	return serialController.close();
}
connect.addEventListener('pointerdown', () => {
	if(connect.value == 'Close') {
		DeviceStop();
	} else {
		serialController.init();
	}
});
fwriter.onclick = async function() {
	fwriter.disabled = true;
	bunlock.disabled = true;
	berase.disabled = true;
	breset.disabled = true;
	connect.disabled = true;
	await FlashWrite();
	connect.disabled = false;
	bunlock.disabled = false;
	berase.disabled = false;
	breset.disabled = false;
	fwriter.disabled = false;
};
bunlock.onclick = async function() {
	fwriter.disabled = true;
	bunlock.disabled = true;
	berase.disabled = true;
	breset.disabled = true;
	connect.disabled = true;
	await Activate(uatime.value);
   	swrite.innerHTML = 'Unlocked!';
	log('Flash Erase All (3.5 sec)...');
	await FlashWriteEnable();
	await FlashUnlock();
	await delay(3500);
	log('Done.');
	connect.disabled = false;
	bunlock.disabled = false;
	berase.disabled = false;
	breset.disabled = false;
	if(connect.opened && firmwareArray != null)
		fwriter.disabled = false;
};
berase.onclick = async function() {
	fwriter.disabled = true;
	bunlock.disabled = true;
	berase.disabled = true;
	breset.disabled = true;
	connect.disabled = true;
	await Activate(uatime.value);
   	swrite.innerHTML = 'Erased!';
	log('Flash Erase All (3.5 sec)...');
	await FlashWriteEnable();
	await FlashEraseAll();
	await delay(3500);
	log('Done.');
	connect.disabled = false;
	bunlock.disabled = false;
	berase.disabled = false;
	breset.disabled = false;
	if(connect.opened && firmwareArray != null)
		fwriter.disabled = false;
};
breset.onclick = async function() {
	fwriter.disabled = true;
	bunlock.disabled = true;
	berase.disabled = true;
	breset.disabled = true;
	connect.disabled = true;
	await Activate(uatime.value);
	log('Soft Reset MCU');
   	swrite.innerHTML = '';
	await SoftResetMSU();
	log('Done.');
	connect.disabled = false;
	bunlock.disabled = false;
	berase.disabled = false;
	breset.disabled = false;
	if(connect.opened && firmwareArray != null)
		fwriter.disabled = false;
};
ufile.onclick = function(){ 
  ufile.value = ""; 
};
window.onload = function() {
    document.querySelector("#file").addEventListener("change", function() {
        var reader = new FileReader();
        reader.onload = function() {
            firmwareArray = this.result;
            log("File was selected, size: " + firmwareArray.byteLength + " bytes");
            if(firmwareArray.byteLength < 16 || (new Uint32Array(firmwareArray.slice(8,12)))[0] != 0x544C4E4B){
				log("Select file is no telink firmware .bin");
				alert("Select file is no telink firmware .bin");
				firmwareArray = null;
				return;
			}
			if(connect.opened) {
				fwriter.disabled = false;
				swrite.innerHTML = '';
			}
        }
        if (this.files[0] != null)
            reader.readAsArrayBuffer(this.files[0]);
        else
            log("No file selected");
    }, false);
}
//---------------------------------
class SerialController {
	async init(init_cb) {
		if ('serial' in navigator) {
			try {
				connect.disabled = true;
				this.port = await navigator.serial.requestPort();
				await this.port.open({baudRate: ubaud.value, baudrate: ubaud.value,
				bufferSize: 240, buffersize: 240}); // % 10, 60..n <= USB-COM Chip fifo
				this.writer = this.port.writable.getWriter();
				console.log('DTR, RTS on.');
				await this.port.setSignals({dataTerminalReady: false, requestToSend: false});
				connect.value = 'Close';
				log('USB-COM opened.');
				connect.opened = true;
				berase.disabled = false;
				bunlock.disabled = false;
				breset.disabled = false;
				if(firmwareArray != null) {
					fwriter.disabled = false;
					swrite.innerHTML = '';
				}
				if (typeof init_cb == 'function') await init_cb(this.port);
			}
			catch (err) {
				log('There was an error opening the serial port: ' + err);
				berase.disabled = true;
				bunlock.disabled = true;
				breset.disabled = true;
				fwriter.disabled = true;
			}
			connect.disabled = false;
		}
		else {
			log('Web serial doesn\'t seem to be enabled in your browser. Try enabling it by visiting:');
			log('chrome://flags/#enable-experimental-web-platform-features');
			log('opera://flags/#enable-experimental-web-platform-features');
			log('edge://flags/#enable-experimental-web-platform-features');
			alert('Web serial doesn\'t seem to be enabled in your browser. Try enabling it by visiting:\r\nchrome://flags/#enable-experimental-web-platform-features\r\nopera://flags/#enable-experimental-web-platform-features\r\nedge://flags/#enable-experimental-web-platform-features');
			connect.disabled = false;
			connect.opened = false;
			bunlock.disabled = true;
			berase.disabled = true;
			breset.disabled = true;
			fwriter.disabled = true;
		}
	}
	async write_raw(data) {
		return await this.writer.write(data);
	}
	async reset(t_ms) {
		console.log('DTR, RTS off.');
		await this.port.setSignals({dataTerminalReady: true, requestToSend: true});
		await delay(t_ms);
		console.log('DTR, RTS on.');
		return await this.port.setSignals({dataTerminalReady: false, requestToSend: false});
	}
	async close() {
		fwriter.disabled = true;
		swrite.innerHTML = '';
		await this.writer.close();
		await this.port.close();
		connect.value = 'Open';
		connect.opened = false;
		fwriter.disabled = true;
		bunlock.disabled = true;
		berase.disabled = true;
		breset.disabled = true;
		log('USB-COM closed.');
		connect.disabled = false;
	}
}
var serialController = new SerialController();
</script>

</body></html>